use num_enum::{IntoPrimitive, TryFromPrimitive};

use crate::{bindings, const_conversions};

/// ioctl requests
///
/// While the `ioctl` syscall takes the request as an `unsigned long`, which is
/// 64-bits on x86-64, the constants are specifically documented as being
/// 32-bits, so we use an underlying representation of 32-bits.
#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum IoctlRequest {
    TCGETS = bindings::LINUX_TCGETS,
    TCSETS = bindings::LINUX_TCSETS,
    TCSETSW = bindings::LINUX_TCSETSW,
    TCSETSF = bindings::LINUX_TCSETSF,
    TCGETA = bindings::LINUX_TCGETA,
    TCSETA = bindings::LINUX_TCSETA,
    TCSETAW = bindings::LINUX_TCSETAW,
    TCSETAF = bindings::LINUX_TCSETAF,
    TCSBRK = bindings::LINUX_TCSBRK,
    TCXONC = bindings::LINUX_TCXONC,
    TCFLSH = bindings::LINUX_TCFLSH,
    TIOCEXCL = bindings::LINUX_TIOCEXCL,
    TIOCNXCL = bindings::LINUX_TIOCNXCL,
    TIOCSCTTY = bindings::LINUX_TIOCSCTTY,
    TIOCGPGRP = bindings::LINUX_TIOCGPGRP,
    TIOCSPGRP = bindings::LINUX_TIOCSPGRP,
    TIOCOUTQ = bindings::LINUX_TIOCOUTQ,
    TIOCSTI = bindings::LINUX_TIOCSTI,
    TIOCGWINSZ = bindings::LINUX_TIOCGWINSZ,
    TIOCSWINSZ = bindings::LINUX_TIOCSWINSZ,
    TIOCMGET = bindings::LINUX_TIOCMGET,
    TIOCMBIS = bindings::LINUX_TIOCMBIS,
    TIOCMBIC = bindings::LINUX_TIOCMBIC,
    TIOCMSET = bindings::LINUX_TIOCMSET,
    TIOCGSOFTCAR = bindings::LINUX_TIOCGSOFTCAR,
    TIOCSSOFTCAR = bindings::LINUX_TIOCSSOFTCAR,
    FIONREAD = bindings::LINUX_FIONREAD,
    TIOCLINUX = bindings::LINUX_TIOCLINUX,
    TIOCCONS = bindings::LINUX_TIOCCONS,
    TIOCGSERIAL = bindings::LINUX_TIOCGSERIAL,
    TIOCSSERIAL = bindings::LINUX_TIOCSSERIAL,
    TIOCPKT = bindings::LINUX_TIOCPKT,
    FIONBIO = bindings::LINUX_FIONBIO,
    TIOCNOTTY = bindings::LINUX_TIOCNOTTY,
    TIOCSETD = bindings::LINUX_TIOCSETD,
    TIOCGETD = bindings::LINUX_TIOCGETD,
    TCSBRKP = bindings::LINUX_TCSBRKP,
    TIOCSBRK = bindings::LINUX_TIOCSBRK,
    TIOCCBRK = bindings::LINUX_TIOCCBRK,
    TIOCGSID = bindings::LINUX_TIOCGSID,
    TIOCGRS485 = bindings::LINUX_TIOCGRS485,
    TIOCSRS485 = bindings::LINUX_TIOCSRS485,
    TCGETX = bindings::LINUX_TCGETX,
    TCSETX = bindings::LINUX_TCSETX,
    TCSETXF = bindings::LINUX_TCSETXF,
    TCSETXW = bindings::LINUX_TCSETXW,
    TIOCVHANGUP = bindings::LINUX_TIOCVHANGUP,
    FIONCLEX = bindings::LINUX_FIONCLEX,
    FIOCLEX = bindings::LINUX_FIOCLEX,
    FIOASYNC = bindings::LINUX_FIOASYNC,
    TIOCSERCONFIG = bindings::LINUX_TIOCSERCONFIG,
    TIOCSERGWILD = bindings::LINUX_TIOCSERGWILD,
    TIOCSERSWILD = bindings::LINUX_TIOCSERSWILD,
    TIOCGLCKTRMIOS = bindings::LINUX_TIOCGLCKTRMIOS,
    TIOCSLCKTRMIOS = bindings::LINUX_TIOCSLCKTRMIOS,
    TIOCSERGSTRUCT = bindings::LINUX_TIOCSERGSTRUCT,
    TIOCSERGETLSR = bindings::LINUX_TIOCSERGETLSR,
    TIOCSERGETMULTI = bindings::LINUX_TIOCSERGETMULTI,
    TIOCSERSETMULTI = bindings::LINUX_TIOCSERSETMULTI,
    TIOCMIWAIT = bindings::LINUX_TIOCMIWAIT,
    TIOCGICOUNT = bindings::LINUX_TIOCGICOUNT,
    FIOQSIZE = bindings::LINUX_FIOQSIZE,
    FIOSETOWN = bindings::LINUX_FIOSETOWN,
    SIOCSPGRP = bindings::LINUX_SIOCSPGRP,
    FIOGETOWN = bindings::LINUX_FIOGETOWN,
    SIOCGPGRP = bindings::LINUX_SIOCGPGRP,
    SIOCATMARK = bindings::LINUX_SIOCATMARK,
    SOCK_IOC_TYPE = bindings::LINUX_SOCK_IOC_TYPE,
    EPOLL_IOC_TYPE = bindings::LINUX_EPOLL_IOC_TYPE,
    SIOCGSTAMP = bindings::LINUX_SIOCGSTAMP,
    SIOCGSTAMPNS = bindings::LINUX_SIOCGSTAMPNS,
    SIOCADDRT = bindings::LINUX_SIOCADDRT,
    SIOCDELRT = bindings::LINUX_SIOCDELRT,
    SIOCRTMSG = bindings::LINUX_SIOCRTMSG,
    SIOCGIFNAME = bindings::LINUX_SIOCGIFNAME,
    SIOCSIFLINK = bindings::LINUX_SIOCSIFLINK,
    SIOCGIFCONF = bindings::LINUX_SIOCGIFCONF,
    SIOCGIFFLAGS = bindings::LINUX_SIOCGIFFLAGS,
    SIOCSIFFLAGS = bindings::LINUX_SIOCSIFFLAGS,
    SIOCGIFADDR = bindings::LINUX_SIOCGIFADDR,
    SIOCSIFADDR = bindings::LINUX_SIOCSIFADDR,
    SIOCGIFDSTADDR = bindings::LINUX_SIOCGIFDSTADDR,
    SIOCSIFDSTADDR = bindings::LINUX_SIOCSIFDSTADDR,
    SIOCGIFBRDADDR = bindings::LINUX_SIOCGIFBRDADDR,
    SIOCSIFBRDADDR = bindings::LINUX_SIOCSIFBRDADDR,
    SIOCGIFNETMASK = bindings::LINUX_SIOCGIFNETMASK,
    SIOCSIFNETMASK = bindings::LINUX_SIOCSIFNETMASK,
    SIOCGIFMETRIC = bindings::LINUX_SIOCGIFMETRIC,
    SIOCSIFMETRIC = bindings::LINUX_SIOCSIFMETRIC,
    SIOCGIFMEM = bindings::LINUX_SIOCGIFMEM,
    SIOCSIFMEM = bindings::LINUX_SIOCSIFMEM,
    SIOCGIFMTU = bindings::LINUX_SIOCGIFMTU,
    SIOCSIFMTU = bindings::LINUX_SIOCSIFMTU,
    SIOCSIFNAME = bindings::LINUX_SIOCSIFNAME,
    SIOCSIFHWADDR = bindings::LINUX_SIOCSIFHWADDR,
    SIOCGIFENCAP = bindings::LINUX_SIOCGIFENCAP,
    SIOCSIFENCAP = bindings::LINUX_SIOCSIFENCAP,
    SIOCGIFHWADDR = bindings::LINUX_SIOCGIFHWADDR,
    SIOCGIFSLAVE = bindings::LINUX_SIOCGIFSLAVE,
    SIOCSIFSLAVE = bindings::LINUX_SIOCSIFSLAVE,
    SIOCADDMULTI = bindings::LINUX_SIOCADDMULTI,
    SIOCDELMULTI = bindings::LINUX_SIOCDELMULTI,
    SIOCGIFINDEX = bindings::LINUX_SIOCGIFINDEX,
    SIOCSIFPFLAGS = bindings::LINUX_SIOCSIFPFLAGS,
    SIOCGIFPFLAGS = bindings::LINUX_SIOCGIFPFLAGS,
    SIOCDIFADDR = bindings::LINUX_SIOCDIFADDR,
    SIOCSIFHWBROADCAST = bindings::LINUX_SIOCSIFHWBROADCAST,
    SIOCGIFCOUNT = bindings::LINUX_SIOCGIFCOUNT,
    SIOCGIFBR = bindings::LINUX_SIOCGIFBR,
    SIOCSIFBR = bindings::LINUX_SIOCSIFBR,
    SIOCGIFTXQLEN = bindings::LINUX_SIOCGIFTXQLEN,
    SIOCSIFTXQLEN = bindings::LINUX_SIOCSIFTXQLEN,
    SIOCETHTOOL = bindings::LINUX_SIOCETHTOOL,
    SIOCGMIIPHY = bindings::LINUX_SIOCGMIIPHY,
    SIOCGMIIREG = bindings::LINUX_SIOCGMIIREG,
    SIOCSMIIREG = bindings::LINUX_SIOCSMIIREG,
    SIOCWANDEV = bindings::LINUX_SIOCWANDEV,
    SIOCOUTQNSD = bindings::LINUX_SIOCOUTQNSD,
    SIOCGSKNS = bindings::LINUX_SIOCGSKNS,
    SIOCDARP = bindings::LINUX_SIOCDARP,
    SIOCGARP = bindings::LINUX_SIOCGARP,
    SIOCSARP = bindings::LINUX_SIOCSARP,
    SIOCDRARP = bindings::LINUX_SIOCDRARP,
    SIOCGRARP = bindings::LINUX_SIOCGRARP,
    SIOCSRARP = bindings::LINUX_SIOCSRARP,
    SIOCGIFMAP = bindings::LINUX_SIOCGIFMAP,
    SIOCSIFMAP = bindings::LINUX_SIOCSIFMAP,
    SIOCADDDLCI = bindings::LINUX_SIOCADDDLCI,
    SIOCDELDLCI = bindings::LINUX_SIOCDELDLCI,
    SIOCGIFVLAN = bindings::LINUX_SIOCGIFVLAN,
    SIOCSIFVLAN = bindings::LINUX_SIOCSIFVLAN,
    SIOCBONDENSLAVE = bindings::LINUX_SIOCBONDENSLAVE,
    SIOCBONDRELEASE = bindings::LINUX_SIOCBONDRELEASE,
    SIOCBONDSETHWADDR = bindings::LINUX_SIOCBONDSETHWADDR,
    SIOCBONDSLAVEINFOQUERY = bindings::LINUX_SIOCBONDSLAVEINFOQUERY,
    SIOCBONDINFOQUERY = bindings::LINUX_SIOCBONDINFOQUERY,
    SIOCBONDCHANGEACTIVE = bindings::LINUX_SIOCBONDCHANGEACTIVE,
    SIOCBRADDBR = bindings::LINUX_SIOCBRADDBR,
    SIOCBRDELBR = bindings::LINUX_SIOCBRDELBR,
    SIOCBRADDIF = bindings::LINUX_SIOCBRADDIF,
    SIOCBRDELIF = bindings::LINUX_SIOCBRDELIF,
    SIOCSHWTSTAMP = bindings::LINUX_SIOCSHWTSTAMP,
    SIOCGHWTSTAMP = bindings::LINUX_SIOCGHWTSTAMP,
    SIOCDEVPRIVATE = bindings::LINUX_SIOCDEVPRIVATE,
    SIOCPROTOPRIVATE = bindings::LINUX_SIOCPROTOPRIVATE,
}

impl IoctlRequest {
    /// Used below for generating checked const aliases.
    const fn alias(existing_member: Self, expected_value: u64) -> Self {
        // We can't use `u64::from` here, in a const context, so we use `as`.
        assert!(existing_member as u64 == expected_value);
        existing_member
    }
    pub const TIOCINQ: Self = Self::alias(
        Self::FIONREAD,
        const_conversions::u64_from_u32(bindings::LINUX_TIOCINQ),
    );
    pub const SIOGIFINDEX: Self = Self::alias(
        Self::SIOCGIFINDEX,
        const_conversions::u64_from_u32(bindings::LINUX_SIOGIFINDEX),
    );
}
